import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.concurrent.*;

public class SnakeGame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                new Snake();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

class Snake extends JFrame {
    // 内部类定义（放在成员变量之前）
    class GamePanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;

            // 绘制游戏区域
            g2.setColor(Color.WHITE);
            g2.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);

            if (isAlive) {
                drawSnake(g2);
                drawFood(g2);
                drawScore(g2);
            } else {
                drawGameOver(g2);
            }
        }

        private void drawSnake(Graphics2D g2) {
            synchronized (snakeBody) {
                g2.setColor(new Color(0, 100, 0)); // 深绿色蛇身
                for (Point segment : snakeBody) {
                    g2.fillRoundRect(segment.x, segment.y, CELL_SIZE, CELL_SIZE, 10, 10);
                }

                // 蛇头不同颜色
                if (!snakeBody.isEmpty()) {
                    Point head = snakeBody.get(snakeBody.size() - 1);
                    g2.setColor(new Color(0, 150, 0)); // 浅绿色蛇头
                    g2.fillRoundRect(head.x, head.y, CELL_SIZE, CELL_SIZE, 10, 10);
                }
            }
        }

        private void drawFood(Graphics2D g2) {
            g2.setColor(Color.RED);
            g2.fillOval(food.getX(), food.getY(), CELL_SIZE, CELL_SIZE);
        }

        private void drawScore(Graphics2D g2) {
            g2.setFont(new Font("微软雅黑", Font.BOLD, 20));
            g2.setColor(Color.BLUE);
            g2.drawString("长度: " + snakeBody.size(), 20, 20);
        }

        private void drawGameOver(Graphics2D g2) {
            g2.setFont(new Font("微软雅黑", Font.BOLD, 50));
            g2.setColor(Color.RED);

            String gameOverText = "游戏结束!";
            FontMetrics fm = g2.getFontMetrics();
            int textWidth = fm.stringWidth(gameOverText);

            g2.drawString(gameOverText, (GAME_WIDTH - textWidth) / 2, GAME_HEIGHT / 2);

            g2.setFont(new Font("微软雅黑", Font.PLAIN, 30));
            String scoreText = "最终长度: " + snakeBody.size();
            textWidth = g2.getFontMetrics().stringWidth(scoreText);
            g2.drawString(scoreText, (GAME_WIDTH - textWidth) / 2, GAME_HEIGHT / 2 + 50);
        }
    }

    class Food {
        private int x, y;
        private final Random random = new Random();

        public Food() {
            respawn();
        }

        public void respawn() {
            // 确保食物不会出现在蛇身上
            while (true) {
                x = random.nextInt(GAME_WIDTH / CELL_SIZE) * CELL_SIZE;
                y = random.nextInt(GAME_HEIGHT / CELL_SIZE) * CELL_SIZE;

                boolean valid = true;
                synchronized (snakeBody) {
                    for (Point segment : snakeBody) {
                        if (segment.x == x && segment.y == y) {
                            valid = false;
                            break;
                        }
                    }
                }

                if (valid) break;
            }
        }

        public int getX() { return x; }
        public int getY() { return y; }
    }

    class SnakeKeyListener extends KeyAdapter {
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    if (direction != DOWN) direction = UP;
                    break;
                case KeyEvent.VK_DOWN:
                    if (direction != UP) direction = DOWN;
                    break;
                case KeyEvent.VK_LEFT:
                    if (direction != RIGHT) direction = LEFT;
                    break;
                case KeyEvent.VK_RIGHT:
                    if (direction != LEFT) direction = RIGHT;
                    break;
                case KeyEvent.VK_SPACE:
                    if (!isAlive) {
                        resetGame();
                    }
                    break;
            }
        }
    }

    // 常量定义
    private static final int UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4;
    private static final int CELL_SIZE = 20;
    private static final int GAME_WIDTH = 800;
    private static final int GAME_HEIGHT = 600;
    private static final int INITIAL_DELAY = 100;

    // 成员变量声明
    private final List<Point> snakeBody = Collections.synchronizedList(new ArrayList<>());
    private volatile int direction = UP;
    private GamePanel gamePanel;
    private volatile boolean isAlive = true;
    private volatile Food food;
    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    public Snake() {
        initGame();
        setupFrame();
        startGame();
    }

    private void initGame() {
        // 初始化蛇身(3节)
        snakeBody.add(new Point(100, 100));
        snakeBody.add(new Point(100, 120));
        snakeBody.add(new Point(100, 140));

        food = new Food();
        gamePanel = new GamePanel();
        add(gamePanel);
        addKeyListener(new SnakeKeyListener());
    }

    private void setupFrame() {
        setTitle("多线程贪吃蛇");
        setSize(GAME_WIDTH, GAME_HEIGHT);
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void startGame() {
        // 游戏逻辑更新任务
        executor.scheduleAtFixedRate(() -> {
            if (isAlive) {
                updateGame();
            }
        }, 0, INITIAL_DELAY, TimeUnit.MILLISECONDS);

        // 渲染任务（在EDT中执行）
        executor.scheduleAtFixedRate(() -> {
            SwingUtilities.invokeLater(gamePanel::repaint);
        }, 0, INITIAL_DELAY, TimeUnit.MILLISECONDS);
    }

    private void updateGame() {
        moveSnake();
        checkFoodCollision();
        checkCollision();
    }

    private void moveSnake() {
        synchronized (snakeBody) {
            Point head = snakeBody.get(snakeBody.size() - 1);
            int newX = head.x;
            int newY = head.y;

            switch (direction) {
                case UP: newY -= CELL_SIZE; break;
                case DOWN: newY += CELL_SIZE; break;
                case LEFT: newX -= CELL_SIZE; break;
                case RIGHT: newX += CELL_SIZE; break;
            }

            // 边界处理(穿墙)
            if (newX < 0) newX = GAME_WIDTH - CELL_SIZE;
            if (newX >= GAME_WIDTH) newX = 0;
            if (newY < 0) newY = GAME_HEIGHT - CELL_SIZE;
            if (newY >= GAME_HEIGHT) newY = 0;

            snakeBody.add(new Point(newX, newY));
            snakeBody.remove(0);
        }
    }

    private void checkFoodCollision() {
        synchronized (snakeBody) {
            Point head = snakeBody.get(snakeBody.size() - 1);
            if (head.equals(new Point(food.getX(), food.getY()))) {
                growSnake();
                food.respawn();
            }
        }
    }

    private void growSnake() {
        synchronized (snakeBody) {
            Point tail = snakeBody.get(0);
            snakeBody.add(0, new Point(tail.x, tail.y));
        }
    }

    private void checkCollision() {
        synchronized (snakeBody) {
            // 蛇身长度小于4时不检测碰撞（初始长度为3）
            if (snakeBody.size() < 4) {
                return;
            }

            Point head = snakeBody.get(snakeBody.size() - 1);
            // 从第1节开始检查（跳过头部紧邻的第0节）
            for (int i = 0; i < snakeBody.size() - 2; i++) {
                if (head.equals(snakeBody.get(i))) {
                    isAlive = false;
                    gameOver();
                    break;
                }
            }
        }
    }

    private void gameOver() {
        executor.shutdown();
        try {
            if (!executor.awaitTermination(500, TimeUnit.MILLISECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    private void resetGame() {
        snakeBody.clear();
        snakeBody.add(new Point(100, 100));
        snakeBody.add(new Point(100, 120));
        snakeBody.add(new Point(100, 140));
        direction = UP;
        isAlive = true;
        food.respawn();
        startGame();
    }
}